"""
Case Type   : 故障&可靠性测试
Case Name   : 表文件丢失,create table未checkpoint情况下重启数据库，验证标文件恢复
Create At   : 2020/07/01
Owner       : @wan005
Description :
    1.设置最大可用模式为on，且关闭备节点
    2.设置检查点相关参数，检查时间设置为10min
    3.创建表，并写入数据
    4.删除表文件
    5.插入数据
    6.重启主节点
    7.再次插入数据
    8.主备数据对比
    9.还原参数
    10.删除表
Expect      :
    1.执行成功
    2.执行成功
    3.执行成功
    4.执行成功
    5.插入数据失败：
    6.重启成功
    7.插入数据成功
    8.数据一致
    9.执行成功
    10.执行成功
History     :
    Modified by: @wan005 将tab转换为空格
    Modified by: @wan005 将正常stop改为kill -9
    Modified by: @li-xin12345 增大插入数据量
    Modified by: @peilinqian 优化用例逻辑，增加增量checkpoint间隔，稳定测试结果
    Modified by: @ningyali 优化用例解决不一致问题
"""
import os
import time
import unittest

from testcase.utils.Common import Common
from testcase.utils.CommonSH import *
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class DelTablefile(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.sta1_sh = CommonSH('Standby1DbUser')
        self.sta2_sh = CommonSH('Standby2DbUser')
        self.dn1_path = macro.DB_INSTANCE_PATH
        self.pri_user = self.pri_sh.node
        self.sta1_user = self.sta1_sh.node
        self.sta2_user = self.sta2_sh.node
        self.com = Common()
        self.Constant = Constant()
        self.t_name = 'reliability_dbsys063'
        self.com_pri = Common('PrimaryRoot')
        self.pri_root = Node(node='PrimaryRoot')
        self.node_num = self.com.get_node_num(self.pri_root)
        self.pri_hostname = self.pri_root.sh('hostname').result()
        self.min_time = 300
        self.init_param1 = self.pri_sh.show_param('most_available_sync')
        self.init_param2 = self.pri_sh.show_param(
            'incremental_checkpoint_timeout')

    def test_deltablefile(self):
        text = '-----step1:设置最大可用模式为on，且关闭备节点; expect:执行成功-----'
        self.log.info(text)
        res = self.pri_sh.executeGsguc(
            'reload', self.Constant.GSGUC_SUCCESS_MSG,
            'most_available_sync=on')
        self.assertTrue(res, '执行失败' + text)

        self.log.info('-----关闭备节点-----')
        result = self.sta1_sh.stopDbInstance()
        self.assertIn(self.Constant.GS_CTL_STOP_SUCCESS_MSG, result)
        result = self.sta2_sh.stopDbInstance()
        self.assertIn(self.Constant.GS_CTL_STOP_SUCCESS_MSG, result)

        text = '-----step2:设置检查点相关参数，检查时间设置为10min; expect:执行成功-----'
        self.log.info(text)
        self.pri_sh.show_param('enable_incremental_checkpoint')
        res = self.pri_sh.executeGsguc(
            'reload', self.Constant.GSGUC_SUCCESS_MSG,
            'incremental_checkpoint_timeout=10min', self.pri_hostname)
        self.assertTrue(res, '执行失败' + text)

        self.log.info('-----重启主机，重新计时auto checkpoint-----')
        result = self.pri_sh.stopDbInstance()
        self.assertIn(self.Constant.GS_CTL_STOP_SUCCESS_MSG, result)
        result = self.pri_sh.startDbInstance('primary')
        self.assertIn(self.Constant.RESTART_SUCCESS_MSG, result)

        text = '-----step3:创建表，并写入数据; expect:执行成功-----'
        self.log.info(text)
        sql = f'drop table if exists {self.t_name}; ' \
              f'create table {self.t_name}(id int); ' \
              f'insert into {self.t_name} values(generate_series(1,100));'
        result = self.pri_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn(self.Constant.insert_success_msg, result, '执行失败' + text)

        text = '-----step4:删除表文件; expect:执行成功-----'
        self.log.info(text)
        self.log.info('-----waiting dirtypage update-----')
        result = self.pri_sh.check_whether_remain_dirty_page()
        self.assertTrue(result, '执行失败' + text)

        self.log.info('-----通过oid查询文件位置-----')
        sql_cmd = f"select pg_relation_filepath(oid::regclass) " \
                  f"from pg_class where relname='{self.t_name}';"
        result = self.pri_sh.executDbSql(sql_cmd)
        rmpath = result.splitlines()[-2].strip()
        self.log.info(rmpath)

        self.log.info('-----delete file--------')
        rm_cmd = f'rm -rf {os.path.join(self.dn1_path, rmpath)};' \
                 f'ls -al {os.path.join(self.dn1_path, rmpath)}'
        self.log.info(rm_cmd)
        msg = self.pri_user.sh(rm_cmd).result()
        self.log.info(msg)
        self.assertIn(self.Constant.NO_FILE_MSG, msg, '执行失败' + text)

        text = '-----step5:插入数据; expect:执行失败-----'
        self.log.info(text)
        sql_cmd = f'insert into {self.t_name} values(' \
                  f'generate_series(1,1000000));'
        result = self.pri_sh.executDbSql(sql_cmd)
        self.assertIn(self.Constant.OPEN_FAIL, result)

        text = '-----step6:重启主节点; expect:重启成功-----'
        self.log.info(text)
        result = self.com_pri.kill_pid(self.pri_root, '9')
        self.log.info(result)

        result = self.pri_sh.startDbCluster()
        self.log.info(result)
        self.assertTrue(result, '执行失败' + text)
        self.log.info('-----查询表文件-----')
        res = self.pri_user.sh(
            f'ls -al {os.path.join(self.dn1_path, rmpath)}').result()
        self.log.info(res)

        text = '-----step7:再次插入数据; expect:插入数据成功-----'
        self.log.info(text)
        sql_cmd = f'insert into {self.t_name} values(generate_series(1,1000));'
        self.log.info(sql_cmd)
        result = self.pri_sh.executDbSql(sql_cmd)
        self.log.info(result)
        self.assertIn('INSERT 0 1000', result, '执行失败' + text)

        text = '-----step8:主备数据对比; expect:数据一致-----'
        self.log.info(text)
        self.log.info('-----查看主备是否同步-----')
        self.pri_sh.check_location_consistency(
            'primary', self.node_num, self.min_time)
        all_user_nodes = (self.pri_user, self.sta1_user, self.sta2_user)
        select_sql = f'select count(*) from {self.t_name};'
        flag = self.com.check_data_sample_by_all(select_sql, *all_user_nodes)
        self.assertTrue(flag, '执行失败' + text)

    def tearDown(self):
        self.log.info('-----this is teardown-----')
        text1 = '-----step9:还原参数; expect:执行成功-----'
        self.log.info(text1)
        result1 = self.pri_sh.executeGsguc(
            'reload', self.Constant.GSGUC_SUCCESS_MSG,
            f'most_available_sync={self.init_param1}')
        self.log.info(result1)
        result2 = self.pri_sh.executeGsguc(
            'reload', self.Constant.GSGUC_SUCCESS_MSG,
            f'incremental_checkpoint_timeout={self.init_param2}')
        self.log.info(result2)

        text2 = '-----step10:删除表; expect:执行成功-----'
        self.log.info(text2)
        sql = f'drop table if exists {self.t_name};'
        result = self.pri_sh.executDbSql(sql)
        self.log.info(result)

        self.assertTrue(result1, '执行失败' + text1)
        self.assertTrue(result2, '执行失败' + text1)
        self.assertIn(
            self.Constant.TABLE_DROP_SUCCESS, result, '执行失败' + text2)
        self.log.info(f'-----{os.path.basename(__file__)} end-----')
